﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace GOFtest
{
    public partial class Builder : Form
    {
        public Builder()
        {
            InitializeComponent();
        }

        //直接绘画，不能重用，容易遗漏
        private void button1_Click(object sender, EventArgs e)
        {
            Pen p = new Pen(Color.Black);
            Graphics gThin = this.pictureBox1.CreateGraphics();

            gThin.DrawEllipse(p, 50, 20, 30, 30);
            gThin.DrawRectangle(p, 60, 50, 10, 50);
            gThin.DrawLine(p, 60, 50, 40, 100);
            gThin.DrawLine(p, 70, 50, 90, 100);
            gThin.DrawLine(p, 60, 100, 45, 150);
            gThin.DrawLine(p, 70, 100, 85, 150);
        }

        #region 建造者模式
        //建造者模式，先定义一个抽象的建造人的类，把这个过程稳定住，不让人遗忘当中的任何一步
        abstract class PersonBuilder
        {
            protected Graphics g;
            protected Pen p;

            public PersonBuilder(Graphics g, Pen p)
            {
                this.g = g;
                this.p = p;
            }

            public abstract void BuildHead();
            public abstract void BuildBody();
            public abstract void BuildArmLeft();
            public abstract void BuildArmRight();
            public abstract void BuildLegLeft();
            public abstract void BuildLegRight();
        }

        //要画一个瘦子，就要继续这个抽象类，实现所有的抽象方法，不会再有遗漏
        class PersonThinBuilder : PersonBuilder
        {
            public PersonThinBuilder(Graphics g, Pen p)
                : base(g, p)
            { }

            public override void BuildHead()
            {
                g.DrawEllipse(p, 50, 20, 30, 30);                
            }

            public override void BuildBody()
            {
                g.DrawRectangle(p, 60, 50, 10, 50);
            }

            public override void BuildArmLeft()
            {
                g.DrawLine(p, 60, 50, 40, 100);                
            }

            public override void BuildArmRight()
            {
                g.DrawLine(p, 70, 50, 90, 100);                
            }

            public override void BuildLegLeft()
            {
                g.DrawLine(p, 60, 100, 45, 150);                
            }

            public override void BuildLegRight()
            {
                g.DrawLine(p, 70, 100, 85, 150);
            }
        }
        //还需要一个建造者模式中最重要的类，指挥者(Director)，用它来控制建造过程，隔离用户与建造过程的关联
        class PersonDirector
        {
            private PersonBuilder pb;
            public PersonDirector(PersonBuilder pb) //用户告诉指挥者，需要什么样的小人
            {
                this.pb = pb;
            }
            public void CreatePerson()
            {
                pb.BuildHead(); //根据用户的选择建造小人
                pb.BuildBody();
                pb.BuildArmLeft();
                pb.BuildArmRight();
                pb.BuildLegLeft();
                pb.BuildLegRight();
            }
        }
        private void button2_Click(object sender, EventArgs e)
        {
            Pen p = new Pen(Color.Black);
            PersonThinBuilder ptb = new PersonThinBuilder(pictureBox2.CreateGraphics(), p);
            PersonDirector pdThin = new PersonDirector(ptb);
            pdThin.CreatePerson();
        }
        #endregion

        #region 模型
        private void button3_Click(object sender, EventArgs e)
        {
            Director director = new Director();
            BuilderDemo b1 = new ConcreteBuilder1();
            BuilderDemo b2 = new ConcreteBuilder2();

            director.Construct(b1); //指挥者用b1来的方法来建造产品
            Product p1 = b1.GetResult();
            p1.Show();

            director.Construct(b2);
            Product p2 = b2.GetResult();
            p2.Show();
        }
        //产品类，由多个部件组成
        class Product
        {
            IList<string> parts = new List<string>();

            public void Add(string part)    //添加产品部件
            {
                parts.Add(part);
            }

            public void Show()
            {
                string outputMsg = "";
                outputMsg = "创建产品----\n";
                foreach (var item in parts)
                {
                    outputMsg += item + "\n";
                }
                MessageBox.Show(outputMsg);
            }
        }
        //Builder类，抽象建造者类，确定产品由两个部件PartA和PartB组成，并声明一个得到产品创建后结果的方法GetResult
        abstract class BuilderDemo
        {
            public abstract void BuildPartA();
            public abstract void BuildPartB();
            public abstract Product GetResult();
        }
        //具体的建造者类
        class ConcreteBuilder1 : BuilderDemo
        {
            private Product product = new Product();

            public override void BuildPartA()
            {
                product.Add("部件A");
            }
            public override void BuildPartB()
            {
                product.Add("部件B");
            }
            public override Product GetResult()
            {
                return product;
            }
        }
        class ConcreteBuilder2 : BuilderDemo
        {
            private Product product = new Product();

            public override void BuildPartA()
            {
                product.Add("部件X");
            }
            public override void BuildPartB()
            {
                product.Add("部件Y");
            }
            public override Product GetResult()
            {
                return product;
            }
        }
        //指挥者类
        class Director
        {
            public void Construct(BuilderDemo builder)
            {
                builder.BuildPartA();
                builder.BuildPartB();
            }
        }
        #endregion

    }
}
